package com.yanqu.road.server.gameplayer.module.wingroom;

import com.yanqu.road.dao.impl.wingroom.UserFurnitureSampleDaoImpl;
import com.yanqu.road.dao.impl.wingroom.UserFurnitureSuitDaoImpl;
import com.yanqu.road.dao.impl.wingroom.UserWingRoomPlanDaoImpl;
import com.yanqu.road.dao.impl.wingroom.WingRoomDataDaoImpl;
import com.yanqu.road.entity.DataStatus;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.config.skill.SkillUpgradeInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.*;
import com.yanqu.road.entity.player.*;
import com.yanqu.road.entity.relatives.RelativesInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.entity.wingroom.*;
import com.yanqu.road.entity.wingroom.chakra.WingRoomChakraFurnitureChangeItem;
import com.yanqu.road.entity.wingroom.config.WingRoomFurnitureConfig;
import com.yanqu.road.entity.wingroom.config.WingRoomLvConfig;
import com.yanqu.road.entity.wingroom.config.WingRoomRegionConfig;
import com.yanqu.road.entity.wingroom.returnentity.DecorateResult;
import com.yanqu.road.logic.bussiness.DaoHelper;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.wingroom.WingRoomProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.mail.MailModule;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.player.BadgeModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.relatives.RelativesModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.*;
import com.yanqu.road.server.manger.config.GoodsBagMgr;
import com.yanqu.road.server.manger.config.HideGoodsMgr;
import com.yanqu.road.server.manger.config.SkillMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.WorldMessageMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.rank.RankMgr;
import com.yanqu.road.server.manger.relatives.RelativesMgr;
import com.yanqu.road.server.manger.union.CrossUnionMgr;
import com.yanqu.road.server.manger.wingroom.WingRoomConfigMgr;
import com.yanqu.road.server.manger.wingroom.WingRoomMgr;
import com.yanqu.road.server.pb.WingRoomPb;
import com.yanqu.road.server.pb.WorldMessagePb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author ：zfr
 * @date ：2022/1/19 14:35
 */
public class WingRoomModule extends GeneralModule {
    //厢房数据
    private UserWingRoomData wingRoomData;
    //家具图鉴数据
    private Map<Integer, UserFurnitureSample> furnitureMap = new ConcurrentHashMap<>();
    //蓝图数据 region-planId-plan
    private Map<Long, UserWingRoomPlan> userPlanMap = new ConcurrentHashMap<>();
    //蓝图最大id
    private long planMaxId = 0L;
    //家具套装数据
    private Map<Integer, UserFurnitureSuitData> suitDataMap = new ConcurrentHashMap<>();
    //拜访门客
    private UserPatronsVisitData patronsVisitData;


    public WingRoomModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        long userId = getUserId();
        wingRoomData = new WingRoomDataDaoImpl().getUserWingRoomData(userId);
        patronsVisitData = DaoHelper.getUserPatronsVisitDataDaoImpl().getUserPatronsVisitData(userId);
        initSystem();
        if (wingRoomData != null) {
            wingRoomData.setPreGetEventRewardTimes(0);
        }

        furnitureMap = new UserFurnitureSampleDaoImpl().getUserFurnitureSampleData(userId);
        userPlanMap = new UserWingRoomPlanDaoImpl().getUserWingRoomPlanMap(userId);
        suitDataMap = new UserFurnitureSuitDaoImpl().getUserFurnitureSuitMap(userId);
        planMaxId = new UserWingRoomPlanDaoImpl().getPlanMaxId(userId);

        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    public UserWingRoomData getWingRoomData() {
        return wingRoomData;
    }

    @Override
    public void loginSendMsg() {
        syncAllData();
    }

    @Override
    public void afterLogin() {
        //跨服取拜访奖励
        fetchCrossVisitReward();

        calVisitRedDot(WingRoomProto.UserWingRoomRedDotSync.newBuilder());

        //临时，检测下跨服亲家，拜访问题
        if(patronsVisitData != null && patronsVisitData.getState() == 0){
            if(patronsVisitData.getUserBaseInfo() == null){
                patronsVisitData.setState(2);
                patronsVisitData.setTodayTouch(false);
                long time = DateHelper.getTodayZeroTimeStamp() / 1000 - DateHelper.DAY_SECONDS * 24;
                patronsVisitData.setEventTime((int)time);
                touchUserPatronsVisitData(null);
            }
        }
    }

    //同步全部数据
    private void syncAllData() {
        userWingRoomDataSync();
        wingRoomRegionSync();
        userFurnitureSampleSync();
        userFurnitureSuitDataSync();
        userWingRoomPlanSync();
        userShareEventSync();
        syncVisitPatrons();
    }

    //玩家基础数据同步
    public void userWingRoomDataSync() {
        if (wingRoomData != null) {
            if(StringUtils.isNullOrEmpty(wingRoomData.getBgm())){
                wingRoomData.setBgm("0");
            }
            player.sendPacket(Protocol.U_WING_ROOM_DATA_SYNC, WingRoomPb.buildUserWingRoomDataMsg(wingRoomData));
        }
    }

    //厢房区域同步
    private void wingRoomRegionSync() {
        if (wingRoomData != null) {
            WingRoomProto.WingRoomRegionSync.Builder syncMsg = WingRoomProto.WingRoomRegionSync.newBuilder();
            for (WingRoomRegion roomRegion : wingRoomData.getRegionMap().values()) {
                syncMsg.addRegion(WingRoomPb.buildWingRoomRegionTempMsg(roomRegion));
            }
            player.sendPacket(Protocol.U_WING_ROOM_REGION_SYNC, syncMsg);
        }
    }

    //玩家家具图鉴同步
    private void userFurnitureSampleSync() {
        WingRoomProto.UserFurnitureSampleSync.Builder syncMsg = WingRoomProto.UserFurnitureSampleSync.newBuilder();
        for (UserFurnitureSample sample : furnitureMap.values()) {
            syncMsg.addFurnitureSample(WingRoomPb.buildFurnitureSampleTempMsg(sample));
        }
        player.sendPacket(Protocol.U_WING_ROOM_FURNITURE_SAMPLE_SYNC, syncMsg);
    }

    private void userFurnitureSuitDataSync() {
        WingRoomProto.FurnitureSuitDataSync.Builder syncMsg = WingRoomProto.FurnitureSuitDataSync.newBuilder();
        for (UserFurnitureSuitData suitData : suitDataMap.values()) {
            syncMsg.addSuitData(WingRoomPb.buildFurnitureSuitDataTemp(suitData));
        }
        player.sendPacket(Protocol.U_WING_ROOM_FURNITURE_SUIT_DATA_SYNC, syncMsg);
    }

    //玩家装修方案列表同步
    public void userWingRoomPlanSync() {
        WingRoomProto.UserWingRoomPlanSync.Builder syncMsg = WingRoomProto.UserWingRoomPlanSync.newBuilder();
        for (UserWingRoomPlan plan : userPlanMap.values()) {
            if (!plan.isDelete()) {
                syncMsg.addPlan(WingRoomPb.buildPlanTempMsg(plan));
            }
        }
        player.sendPacket(Protocol.U_WING_ROOM_PLAN_SYNC, syncMsg);
    }

    //玩家呼朋唤友事件同步
    public void userShareEventSync() {
        UserWingRoomShareEvent userEvent = WingRoomMgr.getUserEvent(player.getUserId());
        if (userEvent != null) {
            boolean resetReward = false;
            for (WingRoomEventReward reward : userEvent.getRewardMap().values()) {
                if (StringUtils.isNullOrEmpty(reward.getReward())) {
                    resetReward = true;
                    break;
                }
            }
            if (resetReward) {
                userEvent.setRewardMap(generateRewardPool());
            }
            WingRoomProto.UserWingRoomShareEventSyncMsg.Builder syncMsg = WingRoomProto.UserWingRoomShareEventSyncMsg.newBuilder();
            syncMsg.setEvent(WingRoomPb.buildEventTempMsg(userEvent));
            player.sendPacket(Protocol.U_WING_ROOM_SHARE_EVENT_SYNC, syncMsg);
        }
    }

    //系统解锁
    public void initSystem() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.WingRoom.getValue())) {
            initWingRoomData();
            initEvent();
            syncAllData();
        }
    }

    //区域解锁
    public int unlockRegion(int regionId) {
        if (wingRoomData == null) {
            return GameErrorCode.E_WING_ROOM_LOCK;
        }

        Map<Integer, WingRoomRegion> regionMap = wingRoomData.getRegionMap();
        //已解锁
        if (regionMap.containsKey(regionId)) {
            return GameErrorCode.E_WING_ROOM_REGION_UNLOCK;
        }

        //配置是否存在
        WingRoomRegionConfig regionConfig = WingRoomConfigMgr.getRegionConfig(regionId);
        if (regionConfig == null) {
            return GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND;
        }

        //是否达到解锁要求
        if (!WingRoomConfigMgr.checkRegionUnlock(regionId, wingRoomData.getLv())) {
            return GameErrorCode.E_WING_ROOM_LV_NO_ENOUGH;
        }

        //解锁成功
        WingRoomRegion region = new WingRoomRegion(regionId, new ArrayList<>());
        wingRoomData.addRegion(region);

        wingRoomRegionSync();

        AutoLogMgr.add(new LogWingRoomRegionUnLock(
                getUserId(),
                regionId,
                wingRoomData.getLv()));
        return 0;
    }

    //解锁家具图鉴
    private int unlockFurnitureSample(int furnitureId, boolean isOneKey) {
        //已解锁
        if (furnitureMap.containsKey(furnitureId)) {
            return GameErrorCode.E_WING_ROOM_FURNITURE_UNLOCK;
        }
        int unlockConsumeRet = furnitureConsume(furnitureId, 1);
        if (unlockConsumeRet != 0) {
            return unlockConsumeRet;
        }
        //解锁家具图鉴
        UserFurnitureSample furnitureSample = new UserFurnitureSample(player.getUserId(), furnitureId, 1, DataStatus.Insert);
        furnitureMap.put(furnitureSample.getFurnitureId(), furnitureSample);
        if (!isOneKey) {
            calcFurnitureComfortValue();
            userWingRoomDataSync();
            player.getModule(PatronsModule.class).onPatronsChange(null);
        }
        return 0;
    }

    //家具解锁/升级消耗
    private int furnitureConsume(int furnitureId, int curLv) {
        //家具配置是否存在
        WingRoomFurnitureConfig furnitureConfig = WingRoomConfigMgr.getFurnitureConfig(furnitureId);
        if (furnitureConfig == null) {
            return GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND;
        }

        //消耗道具是否足够
        int upgradeType = furnitureConfig.getUpgradeType();
        ReturnData returnData = SkillMgr.getUpgradeConsume(upgradeType, curLv);
        if (returnData.getRet() != 0) {
            return returnData.getRet();
        }

        //消耗数量
        BigInteger consumeCount = new BigInteger(returnData.getParams().get(0));
        if (!player.getModule(CurrencyModule.class).removeCurrency(new Property(furnitureId, consumeCount), eLogMoneyType.WingRoom, eLogMoneyType.WingRoomUnlockFurniture)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        AutoLogMgr.add(new LogWingRoomFurnitureLvUp(
                        getUserId(),
                        furnitureId,
                        furnitureConfig.getSuitType(),
                        furnitureConfig.getQuality(),
                        curLv,
                        curLv + 1,
                        consumeCount.intValue()));
        return 0;
    }

    public DecorateResult furniturePlaceChange(List<WingRoomProto.RegionFurniturePlaceChange> placeChangeList) {
        if (wingRoomData == null) {
            return new DecorateResult(GameErrorCode.E_WING_ROOM_LOCK);
        }
        Map<Integer, WingRoomRegion> stashRegionMap = new HashMap<>();
        for (WingRoomRegion region : wingRoomData.getRegionMap().values()) {
            WingRoomRegion regionTemp = region.clone();
            stashRegionMap.put(regionTemp.getRegionId(), regionTemp);
        }
        List<WingRoomChakraFurnitureChangeItem> furnitureChangeList = new ArrayList<>();
        Map<Integer, List<WingRoomFurniture>> regionPlaceFurnitureListMap = new HashMap<>();
        for (WingRoomProto.RegionFurniturePlaceChange regionFurniturePlaceChange : placeChangeList) {
            int regionId = regionFurniturePlaceChange.getRegionId();
            //检查区域合法性
            WingRoomRegion region = stashRegionMap.get(regionId);
            if (region == null) {
                return new DecorateResult(GameErrorCode.E_WING_ROOM_REGION_LOCK);
            }
            //有变动的家具都先移除
            List<WingRoomFurniture> placeFurnitureList = new ArrayList<>();
            for (WingRoomProto.WingRoomFurnitureTemp temp : regionFurniturePlaceChange.getFurnitureList()) {
                if (!temp.getIsRemove()) {
                    WingRoomFurniture changePositionFurniture = WingRoomPb.parseFurniture(temp);
                    placeFurnitureList.add(changePositionFurniture);
                }
                //移除变动
                boolean removeFurnitureFlag = removeFurnitureInListByNo(region.getFurnitureList(), temp.getNo());
                //判断摆放家具，是增加，还是减少
                if (temp.getIsRemove()) {
                    WingRoomChakraFurnitureChangeItem changeItem = new WingRoomChakraFurnitureChangeItem();
                    changeItem.setFurnitureId(temp.getFurnitureId());
                    changeItem.setStatus(false);
                    furnitureChangeList.add(changeItem);
                } else {
                    //判断是否增加家具
                    if (!removeFurnitureFlag) {
                        WingRoomChakraFurnitureChangeItem changeItem = new WingRoomChakraFurnitureChangeItem();
                        changeItem.setFurnitureId(temp.getFurnitureId());
                        changeItem.setStatus(true);
                        furnitureChangeList.add(changeItem);
                    }
                }
            }
            regionPlaceFurnitureListMap.put(regionId, placeFurnitureList);
        }
        DecorateResult result = new DecorateResult(0);
        for (Map.Entry<Integer, List<WingRoomFurniture>> listEntry : regionPlaceFurnitureListMap.entrySet()) {
            DecorateResult decorateResult = placeFurniture(listEntry.getKey(), listEntry.getValue(), stashRegionMap);
            if (decorateResult.getRet() != 0) {
                return decorateResult;
            }
            result.getErrorFurnitureSet().addAll(decorateResult.getErrorFurnitureSet());
        }
        if (result.getErrorFurnitureSet().isEmpty()) {
            wingRoomData.setRegionMap(stashRegionMap);
            //重新计算风水数据。（只计算变化家具，不需要全部循环计算）
            player.getModule(WingRoomChakraModule.class).recountWindWaterData(furnitureChangeList);
        }
        return result;
    }

    private boolean removeFurnitureInListByNo(List<WingRoomFurniture> furnitureList, int no) {
        for (WingRoomFurniture furniture : furnitureList) {
            if (furniture.getNo() == no) {
                furnitureList.remove(furniture);
                return true;
            }
        }
        return false;
    }

    //放置家具
    public DecorateResult placeFurniture(int regionId, List<WingRoomFurniture> furnitureList, Map<Integer, WingRoomRegion> stashMap) {
//        if (wingRoomData == null) {
//            return new DecorateResult(GameErrorCode.E_WING_ROOM_LOCK);
//        }

        //检查区域合法性
//        WingRoomRegion region = wingRoomData.getRegionMap().get(regionId);
//        if (region == null) {
//            return new DecorateResult(GameErrorCode.E_WING_ROOM_REGION_LOCK);
//        }
        WingRoomRegion region = stashMap.get(regionId);
        //检查家具放置合法性
        DecorateResult result = checkDecorateValid(regionId, furnitureList, stashMap);
        if (result.getRet() == 0) {
            region.changeFurnitureList(result.getTempFurnitureList());
        }
        return result;
    }

    //保存家具摆放方案
    public int saveFurniturePlace(List<WingRoomProto.WingRoomRegionTemp> regionList, String planName) {
        long planSize = getRegionPlanSize();
        //超出保存数量上限了
        if (planSize >= GameConfig.WINGROOM_DECORATION_PLAN_NUM) {
            return GameErrorCode.E_WING_ROOM_SAVE_PLAN_SIZE_MAX;
        }

        Map<Integer, WingRoomRegion> stashMap = new HashMap<>();
        for (WingRoomProto.WingRoomRegionTemp regionTemp : regionList) {
            if (!wingRoomData.getRegionMap().containsKey(regionTemp.getRegionId())) {
                return GameErrorCode.E_WING_ROOM_REGION_LOCK;
            }
            stashMap.put(regionTemp.getRegionId(), new WingRoomRegion(regionTemp.getRegionId(), new ArrayList<>()));
            List<WingRoomFurniture> furnitureList = WingRoomPb.parseFurnitureList(regionTemp.getFurnitureList());
            DecorateResult result = checkDecorateValid(regionTemp.getRegionId(), furnitureList, stashMap);
            if (result.getRet() != 0) {
                return result.getRet();
            }
            if (result.getErrorFurnitureSet().size() > 0) {
                return GameErrorCode.E_WING_ROOM_FURNITURE_PLACE_ERROR;
            }
            stashMap.get(regionTemp.getRegionId()).setFurnitureList(result.getTempFurnitureList());
        }
        //检查命名是否合法
        int ret = checkPlanNameValid(planName);
        if (ret != 0) {
            return ret;
        }
        //保存新蓝图
        addNewPlan(stashMap, planName);
        return 0;
    }

    private void addNewPlan(Map<Integer, WingRoomRegion> regionMap, String planName) {
        UserWingRoomPlan plan = new UserWingRoomPlan();
        plan.setUserId(player.getUserId());
        plan.setPlanUid(getPlanNextId());
        plan.setPlanName(planName);
        plan.setRegionMap(regionMap);
        plan.setInsertOption();
        userPlanMap.put(plan.getPlanUid(), plan);
        userWingRoomPlanSync();
    }

    private long getPlanNextId() {
        planMaxId = planMaxId + 1;
        return planMaxId;
    }

    //校验装修方案命名合法性
    public int checkPlanNameValid(String planName) {
        int nameLength = StringUtils.getStringLen(planName);
        int channelId = ServerListMgr.getChannelId(GameServer.getInstance().getServerId());
        if(nameLength > NameMgr.getMaxNickNameLength(channelId)){
            return GameErrorCode.E_NAME_LENGTH_OVER;
        }
        if (!StringUtils.isNumber(planName) && ForbiddenWordMgr.isNickNameForbidden(planName)) {
            return GameErrorCode.E_FORBIDDEN_WORD;
        }
        return 0;
    }

    private long getRegionPlanSize() {
        if (userPlanMap == null) {
            return 0L;
        }
        return userPlanMap.values().stream().filter(plan -> !plan.isDelete()).count();
    }

    //检查装修合法性
    private DecorateResult checkDecorateValid(int regionId, List<WingRoomFurniture> furnitureList, Map<Integer, WingRoomRegion> stashMap) {
        DecorateResult result = new DecorateResult(0);
        HashSet<Integer> furnitureNumErrSet = new HashSet<>();
        //检查区域合法性
        if (!wingRoomData.getRegionMap().containsKey(regionId)) {
            furnitureNumErrSet.addAll(furnitureList.stream().map(WingRoomFurniture::getFurnitureId).collect(Collectors.toList()));
            stashMap.remove(regionId);
            result.setErrorFurnitureSet(furnitureNumErrSet);
            return result;
        }

        //检查一下数量 不够的扣掉
        furnitureNumErrSet.addAll(furnitureIsValid(stashMap, furnitureList));

        //连配置一起打包进去
        List<FurnitureEntityAndConfig> entityAndConfigs = new ArrayList<>();

        //配置有没有
        if (!packageEntityAndConfigList(entityAndConfigs, furnitureList, stashMap.get(regionId))) {
            result.setRet(GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND);
            return result;
        }

        //检查区域是否合法
//        WingRoomRegion region = wingRoomData.getRegionMap().get(regionId);
//        if (region == null) {
//            result.setRet(GameErrorCode.E_WING_ROOM_REGION_LOCK);
//            return result;
//        }
        WingRoomRegionConfig regionConfig = WingRoomConfigMgr.getRegionConfig(regionId);
        if (regionConfig == null) {
            result.setRet(GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND);
            return result;
        }

        WingRoomRegion region = stashMap.get(regionId);

        //检查摆放是否合法
        furnitureNumErrSet.addAll(region.positionIsValid(entityAndConfigs, regionConfig));

        result.setErrorFurnitureSet(furnitureNumErrSet);
        List<WingRoomFurniture> placeList = entityAndConfigs.stream().map(FurnitureEntityAndConfig::getFurnitureEntity).collect(Collectors.toList());
        result.setTempFurnitureList(placeList);
        return result;
    }

    //家具是否合法
    private HashSet<Integer> furnitureIsValid(Map<Integer, WingRoomRegion> stashMap, List<WingRoomFurniture> furnitureList) {
        HashSet<Integer> errFurnitureIds = new HashSet<>();
        boolean hasFloor = false;
        //统计家具数量
        Map<Integer, Integer> usedNumMap = calcUsedFurniture(stashMap);
        //如果是实际装修 要统计一下其他区域使用的家具数量
//        if (decorateType == eDecorateType.Reality.getDecorateType() || decorateType == eDecorateType.DecorateByPlan.getDecorateType()) {
//            usedNumMap = calcOtherRegionUsedFurniture(regionId);
//        }
        //是不是设置了多个地板 并统计一下设置的家具数量
        Iterator<WingRoomFurniture> iterator = furnitureList.iterator();
        while (iterator.hasNext()) {
            WingRoomFurniture furniture = iterator.next();
            if (furniture.isFloor()) {
                if (hasFloor) {

                    try {
                        if (Objects.equals("placeFurniture", Thread.currentThread().getStackTrace()[3].getMethodName())) {
                            log.warn("error floor furniture no:{} id:{} playerId:{}", furniture.getNo(), furniture.getFurnitureId(), getUserId());
                        }
                    } catch (Exception e) {
                        log.error("log furniture error info throw exception", e);
                    }

                    errFurnitureIds.add(furniture.getFurnitureId());
                    iterator.remove();
                    continue;
                }
                hasFloor = true;
            }
            calcFurnitureNum(usedNumMap, furniture);
        }
        //根据玩家家具等级 获取可摆放数量 比较数量是否足够
        for (Map.Entry<Integer, Integer> entry : usedNumMap.entrySet()) {
            int furnitureId = entry.getKey();
            long lackCount = entry.getValue() - getFurnitureCanPlaceCount(furnitureId);
            if (lackCount > 0) {
                errFurnitureIds.add(furnitureId);
                Iterator<WingRoomFurniture> iter = furnitureList.iterator();
                while (iter.hasNext() && lackCount > 0) {
                    WingRoomFurniture furniture = iter.next();
                    if (furniture.getFurnitureId() == furnitureId) {

                        try {
                            if (Objects.equals("placeFurniture", Thread.currentThread().getStackTrace()[3].getMethodName())) {
                                log.warn("error furniture num no enough no:{} id:{} playerId:{}", furniture.getNo(), furniture.getFurnitureId(), getUserId());
                            }
                        } catch (Exception e) {
                            log.error("log furniture error info throw exception", e);
                        }

                        iter.remove();
                        lackCount--;
                    }
                }
            }
        }
        return errFurnitureIds;
    }

    //获取家具可摆放数量
    private long getFurnitureCanPlaceCount(int furnitureId) {
        WingRoomFurnitureConfig furnitureConfig = WingRoomConfigMgr.getFurnitureConfig(furnitureId);
        UserFurnitureSample furnitureSample = furnitureMap.get(furnitureId);
        if (furnitureSample == null || furnitureConfig == null) {
            return 0L;
        }
        int placeNumUpgradeType = furnitureConfig.getPlaceNum();
        SkillUpgradeInfo skillUpgradeInfo = SkillMgr.getSkillUpgradeInfo(placeNumUpgradeType, furnitureSample.getLv());
        if (skillUpgradeInfo == null) {
            return 0L;
        }
        return skillUpgradeInfo.getConsumeCount();
    }

    private boolean packageEntityAndConfigList(List<FurnitureEntityAndConfig> entityAndConfigs, List<WingRoomFurniture> furnitureList, WingRoomRegion region) {
        for (WingRoomFurniture furniture : furnitureList) {
            FurnitureEntityAndConfig entityAndConfig = packageFurnitureEntityAndConfig(furniture);
            if (entityAndConfig == null) {
                return false;
            }
            entityAndConfigs.add(entityAndConfig);
        }

        if (region.getFurnitureList() != null) {
            for (WingRoomFurniture furniture : region.getFurnitureList()) {
                FurnitureEntityAndConfig entityAndConfig = packageFurnitureEntityAndConfig(furniture);
                if (entityAndConfig == null) {
                    return false;
                }
                entityAndConfigs.add(entityAndConfig);
            }
        }
        return true;
    }

    private FurnitureEntityAndConfig packageFurnitureEntityAndConfig(WingRoomFurniture wingRoomFurniture) {
        //配置存在
        WingRoomFurnitureConfig furnitureConfig = WingRoomConfigMgr.getFurnitureConfig(wingRoomFurniture.getFurnitureId());
        if (furnitureConfig == null) {
            return null;
        }
        return new FurnitureEntityAndConfig(wingRoomFurniture, furnitureConfig);
    }

    //统计其他区域家具的摆放数量
    private Map<Integer, Integer> calcUsedFurniture(Map<Integer, WingRoomRegion> stashMap) {
        Map<Integer, Integer> furnitureUsedNumMap = new ConcurrentHashMap<>();
        for (WingRoomRegion region : stashMap.values()) {
            for (WingRoomFurniture furniture : region.getFurnitureList()) {
                calcFurnitureNum(furnitureUsedNumMap, furniture);
            }
        }
        return furnitureUsedNumMap;
    }

    private void calcFurnitureNum(Map<Integer, Integer> furnitureUsedNumMap, WingRoomFurniture furniture) {
        if (!furnitureUsedNumMap.containsKey(furniture.getFurnitureId())) {
            furnitureUsedNumMap.put(furniture.getFurnitureId(), 0);
        }
        int num = furnitureUsedNumMap.get(furniture.getFurnitureId());
        furnitureUsedNumMap.put(furniture.getFurnitureId(), num + 1);
    }

    //蓝图改名
    public int changePlanName(long planUid, String planName) {
        UserWingRoomPlan plan = getPlan(planUid);
        if (plan == null) {
            return GameErrorCode.E_WING_ROOM_PLAN_NO_FOUND;
        }
        planName = StringUtils.clearHeadAndTailEmpty(planName);
        int ret = checkPlanNameValid(planName);
        if (ret != 0) {
            return ret;
        }
        plan.setPlanName(planName);
        userWingRoomPlanSync();
        return 0;
    }

    //删除蓝图
    public int deletePlan(long planUid) {
        UserWingRoomPlan plan = getPlan(planUid);
        if (plan == null) {
            return GameErrorCode.E_WING_ROOM_PLAN_NO_FOUND;
        }
        plan.setDelete(true);
        userWingRoomPlanSync();
        return 0;
    }

    public UserWingRoomPlan getPlan(long planUid) {
        return userPlanMap.get(planUid);
    }

    //使用装修方案
    public WingRoomProto.UsePlanRespMsg.Builder usePlan(long planUid) {
        WingRoomProto.UsePlanRespMsg.Builder respMsg = WingRoomProto.UsePlanRespMsg.newBuilder();
        UserWingRoomPlan plan = getPlan(planUid);
        if (plan == null) {
            respMsg.setRet(GameErrorCode.E_WING_ROOM_PLAN_NO_FOUND);
            return respMsg;
        }
        Map<Integer, WingRoomRegion> stashRegionMap = new HashMap<>();
        for (WingRoomRegion planRegion : plan.getRegionMap().values()) {
            WingRoomRegion region = planRegion.clone();
            stashRegionMap.put(region.getRegionId(), new WingRoomRegion(region.getRegionId(), new ArrayList<>()));
            DecorateResult result = placeFurniture(region.getRegionId(), region.getFurnitureList(), stashRegionMap);
            respMsg.setRet(result.getRet());
            if (result.getErrorFurnitureSet().size() > 0) {
                respMsg.addAllFurnitureId(result.getErrorFurnitureSet());
            }
            if (result.getRet() != 0) {
                return respMsg;
            }
        }
        Map<Integer, WingRoomRegion> regionMap = wingRoomData.getRegionMap();
        for (WingRoomRegion region : regionMap.values()) {
            if (stashRegionMap.containsKey(region.getRegionId())) {
                region.setFurnitureList(stashRegionMap.get(region.getRegionId()).getFurnitureList());
            } else {
                region.setFurnitureList(new ArrayList<>());
            }
        }
        wingRoomData.setUpdateOption();
        for (WingRoomRegion region : wingRoomData.getRegionMap().values()) {
            if (region != null) {
                respMsg.addRegion(WingRoomPb.buildWingRoomRegionTempMsg(region));
            }
        }
        //计算风水数据，并同步
        player.getModule(WingRoomChakraModule.class).recountWindWaterData();
        return respMsg;
    }

    //家具图鉴升级
    public int furnitureSampleLvUp(int furnitureId) {
        UserFurnitureSample furnitureSample = furnitureMap.get(furnitureId);
        if (furnitureSample == null) {
            return unlockFurnitureSample(furnitureId, false);
        }
        int upgradeConsumeRet = furnitureConsume(furnitureId, furnitureSample.getLv());
        if (upgradeConsumeRet != 0) {
            return upgradeConsumeRet;
        }
        furnitureSample.setLv(furnitureSample.getLv() + 1);
        calcFurnitureComfortValue();
        userWingRoomDataSync();
        player.getModule(PatronsModule.class).onPatronsChange(null);
        return 0;
    }

    //家具图鉴升级
    public int furnitureSampleLvUpOneKey() {
        //long oldTime = System.currentTimeMillis();
        int ret = 0;
        WingRoomProto.FurnitureSampleLvUpRespMsg.Builder respMsg = WingRoomProto.FurnitureSampleLvUpRespMsg.newBuilder();
        Map<Integer, WingRoomFurnitureConfig> furnitureConfigMap = WingRoomConfigMgr.getFurnitureConfigMap();
        if (furnitureConfigMap == null) {
            respMsg.setRet(GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND);
            player.sendPacket(Protocol.U_WING_ROOM_FURNITURE_SAMPLE_LV_UP, respMsg);
        }
        for (WingRoomFurnitureConfig furnitureSampleCfg : furnitureConfigMap.values()) {
            if (furnitureSampleCfg == null) {
                ret = GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND;
                continue;
            }
            UserFurnitureSample furnitureSample = furnitureMap.get(furnitureSampleCfg.getFurnitureId());
            boolean isNew = false;
            if (furnitureSample == null) {
                ret = unlockFurnitureSample(furnitureSampleCfg.getFurnitureId(), true);
                if (ret != 0) {
                    continue;
                }
                isNew = true;
                furnitureSample = furnitureMap.get(furnitureSampleCfg.getFurnitureId());
            }

            int oldLv = isNew ? 0 : furnitureSample.getLv();
            do {
                int upgradeConsumeRet = furnitureConsume(furnitureSampleCfg.getFurnitureId(), furnitureSample.getLv());
                if (upgradeConsumeRet != 0) {
                    ret = upgradeConsumeRet;
                    break;
                }
                furnitureSample.setLv(furnitureSample.getLv() + 1);
            } while (true);

            if (oldLv == furnitureSample.getLv()) {
                continue;
            }

//            //解锁/升级家具，风水上限提升
//            player.getModule(WingRoomChakraModule.class).addWindWaterLimit(furnitureSampleCfg.getFurnitureId());

            StringBuilder rewardStr = new StringBuilder();
            for (int lv = oldLv + 1; lv <= furnitureSample.getLv(); lv++) {
                //升级奖励领取
                Property reward = player.getModule(WingRoomChakraModule.class).upgradeFurnitureRewardGet(furnitureSample.getFurnitureId(), lv);
                if (rewardStr.toString().isEmpty()) {
                    rewardStr.append(PropertyHelper.parsePropertyToString(reward));
                } else {
                    rewardStr.append(";").append(PropertyHelper.parsePropertyToString(reward));
                }
            }
            //pb
            respMsg.addSampleList(WingRoomPb.buildFurnitureSampleTempMsg(furnitureSample));
            respMsg.addRewardList(rewardStr.toString());
        }
        if (respMsg.getSampleListList() != null && !respMsg.getSampleListList().isEmpty()) {
            ret = 0;
        }
        respMsg.setRet(ret);
        calcFurnitureComfortValue();
        userWingRoomDataSync();
        player.getModule(PatronsModule.class).onPatronsChange(null);
        player.sendPacket(Protocol.U_WING_ROOM_FURNITURE_SAMPLE_LV_UP, respMsg);
        //log.debug("厢房一键升级耗时：{}", System.currentTimeMillis() - oldTime);
        return ret;
    }

    //厢房升级
    public int wingRoomLvUp() {
        //厢房未解锁
        if (wingRoomData == null) {
            return GameErrorCode.E_WING_ROOM_LOCK;
        }
        int curLv = wingRoomData.getLv();
        WingRoomLvConfig wingRoomCurLvConfig = WingRoomConfigMgr.getWingRoomLvConfig(curLv);
        WingRoomLvConfig wingRoomNextLvConfig = WingRoomConfigMgr.getWingRoomLvConfig(curLv + 1);

        //配置没有 判断已满级
        if ((wingRoomCurLvConfig == null) || wingRoomNextLvConfig == null) {
            return GameErrorCode.E_WING_ROOM_LV_MAX;
        }

        //舒适度不够
        if (wingRoomData.getComfortValue() < wingRoomCurLvConfig.getNeedComfort()) {
            return GameErrorCode.E_WING_ROOM_COMFORT_VALUE_NO_ENOUGH;
        }

        wingRoomData.setLv(wingRoomData.getLv() + 1);
        userWingRoomDataSync();
        changeComfortValueRank();
        // 更新徽章
        updateBadge();
        AutoLogMgr.add(new LogWingRoomLvUp(
                getUserId(),
                wingRoomData.getComfortValue(),
                curLv,
                wingRoomData.getLv()));
        return 0;
    }

    //刷新事件
    public void refreshEvent() {
        if (wingRoomData == null) {
            return;
        }
        //根据状态以及上一次刷新的时间判断是否需要刷新呼朋唤友事件
        UserWingRoomShareEvent userEvent = WingRoomMgr.getUserEvent(player.getUserId());
        if (userEvent == null) {
            return;
        }
        if (userEvent.getStatus() != eWingRoomEventStatus.None.getStatus()) {
            return;
        }
        long judgeTimes;
        if (userEvent.getLastUpdateTime() == 0) {
            judgeTimes = 1;
        } else {
            long duringTime = System.currentTimeMillis() - userEvent.getLastUpdateTime();
            //判定次数
            judgeTimes = duringTime / (GameConfig.WINGROOM_FIND_FRIENDS_REFRESH_TIME * DateHelper.HOUR_MILLIONS);
        }

        for (int i = 0; i < judgeTimes; i++) {
            if (judgeRefreshEvent(userEvent.getJudgeFailTimes())) {
                //判定成功 事件触发
                triggerEvent(userEvent);
                WingRoomMgr.getLogger().debug("---------玩家：{}，触发事件", player.getUserId());
                break;
            }
            //判定失败 记录判定失败的次数
            userEvent.setJudgeFailTimes(userEvent.getJudgeFailTimes() + 1);
            userEvent.setLastUpdateTime(userEvent.getLastUpdateTime() + GameConfig.WINGROOM_FIND_FRIENDS_REFRESH_TIME * DateHelper.HOUR_MILLIONS);
        }
        if (userEvent.getStatus() > eWingRoomEventStatus.None.getStatus()) {
            userShareEventSync();
        }
    }

    //事件触发
    private void triggerEvent(UserWingRoomShareEvent userEvent) {
        try {
            //生成奖励池
            userEvent.setRewardMap(generateRewardPool());
        } catch (Exception e) {
            log.error("generate wing-room event reward pool error:", e);
        }

        long nowTime = System.currentTimeMillis();
        userEvent.setJudgeFailTimes(0);
        userEvent.setTriggerTime(nowTime);
        userEvent.setLastUpdateTime(nowTime);
        userEvent.setShareUnionUid("");
        userEvent.setStatus(eWingRoomEventStatus.Trigger.getStatus()); //初始态
        log.info("trigger wingRoom event userId:{}", getUserId());

    }

    //生成奖励池
    private Map<Integer, WingRoomEventReward> generateRewardPool() {
        Map<Integer, WingRoomEventReward> rewardPool = new ConcurrentHashMap<>();
        List<Property> rewardList = new ArrayList<>();
        String boxRule = GameConfig.WINGROOM_FIND_FRIENDS_REFRESH_BOX_RULE;
        String[] rewardPoolArray = boxRule.split("\\|");
        for (String rewardPoolParam : rewardPoolArray) {
            String[] param = rewardPoolParam.split(",");
            int boxId = Integer.parseInt(param[0]);
            int count = Integer.parseInt(param[1]);
            for (int i = 0; i < count; i++) {
                //随机道具
                OpenGoodsBagResult randomGoods = GoodsBagMgr.getRandomGoods(boxId);
                rewardList.add(randomGoods.getReward());
            }
        }
        //生成后打乱顺序
        Collections.shuffle(rewardList);
        int pos = 0;
        for (Property reward : rewardList) {
            WingRoomEventReward eventReward = new WingRoomEventReward();
            eventReward.setPos(pos);
            eventReward.setReward(PropertyHelper.parsePropertyToString(reward));
            rewardPool.put(pos, eventReward);
            pos++;
        }
        return rewardPool;
    }

    //是否刷新事件判定
    private boolean judgeRefreshEvent(int judgeFailTimes) {
        int baseWight = ConfigMgr.getShareEventRefreshBaseWeight();
        int realWeight = Math.min(ConfigMgr.getShareEventRefreshMaxWeight(), baseWight + (judgeFailTimes * ConfigMgr.getShareEventRefreshAddWeight()));
        return new RandomHelper().next(1000) < realWeight;
    }


    //初始化呼朋唤友事件
    private void initEvent() {
        UserWingRoomShareEvent userEvent = new UserWingRoomShareEvent();
        userEvent.setUserId(player.getUserId());
        userEvent.setStatus(eWingRoomEventStatus.None.getStatus());
        userEvent.setLastUpdateTime(0);
        userEvent.setNeedSync(true);
        userEvent.setInsertOption();
        WingRoomMgr.addEvent(userEvent);
    }

    //领取自己事件的奖励
    public ReturnData getSelfEventReward(int pos) {
        ReturnData returnData = new ReturnData(0);
        UserWingRoomShareEvent userEvent = WingRoomMgr.getUserEvent(player.getUserId());
        if (userEvent == null) {
            returnData.setRet(GameErrorCode.E_WING_ROOM_SHARE_EVENT_NO_FOUND);
            return returnData; //事件不存在
        }
        if (userEvent.getStatus() != eWingRoomEventStatus.Trigger.getStatus()) {
            returnData.setRet(GameErrorCode.E_WING_ROOM_SHARE_EVENT_GET_REWARD_ALREADY);
            return returnData;  //已领奖
        }
        long nowTime = System.currentTimeMillis();
        if (nowTime - userEvent.getTriggerTime() > GameConfig.WINGROOM_FIND_FRIENDS_PICK_UP_TIME * DateHelper.HOUR_MILLIONS) {
            returnData.setRet(GameErrorCode.E_WING_ROOM_SHARE_EVENT_OVER_TIME);
            return returnData;  //超时未领取
        }
        Map<Integer, WingRoomEventReward> rewardMap = userEvent.getRewardMap();
        WingRoomEventReward reward = rewardMap.get(pos);
        if (reward == null) {
            returnData.setRet(GameErrorCode.E_WING_ROOM_SHARE_EVENT_REWARD_NO_FOUND);
            return returnData;  //奖励不存在
        }
        if (reward.isGetReward()) {
            returnData.setRet(GameErrorCode.E_WING_ROOM_SHARE_EVENT_REWARD_GET_ALREADY);
            return returnData;  //奖励已被领取
        }
        reward.setGetReward(true);
        reward.setGetTime(nowTime);
        reward.setPlayerName(player.getUserInfo().getNickName());
        reward.setPlayerId(player.getUserId());
        Property property = PropertyHelper.parseStringToProperty(reward.getReward());
        property.addProperty(new Property(101044, BigInteger.valueOf(GameConfig.WINGROOM_FIND_FRIENDS_FURNITURE_MONEY_MIN)));
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.WingRoom, eLogMoneyType.WingRoomGetEventReward);
        userEvent.setStatus(eWingRoomEventStatus.GetReward.getStatus());
        userEvent.setGetRewardTime(nowTime);
        userEvent.setLastUpdateTime(nowTime);
        userEvent.setNeedSync(true);
        reward.setReward(PropertyHelper.parsePropertyToString(property));
        returnData.addParam(reward.getReward());
        if (returnData.getRet() == 0) {
            AutoLogMgr.add(new LogWingRoomShareEventReward(
                    getUserId(),
                    userEvent.getUserId(),
                    reward.getReward(),
                    new Date(userEvent.getTriggerTime()),
                    new Date(userEvent.getGetRewardTime()))
            );
        }
        player.notifyListener(eGamePlayerEventType.WingRoomGetEventRewardTimes.getValue(),1);
        return returnData;
    }

    //呼朋唤友
    public int shareEvent(int shareType) {
        UserWingRoomShareEvent userEvent = WingRoomMgr.getUserEvent(player.getUserId());
        if (userEvent == null) {
            return GameErrorCode.E_WING_ROOM_SHARE_EVENT_NO_FOUND;  //事件不存在
        }

        long nowTime = System.currentTimeMillis();

        if (userEvent.getStatus() != eWingRoomEventStatus.GetReward.getStatus() ||
                nowTime - userEvent.getGetRewardTime() > GameConfig.WINGROOM_FIND_FRIENDS_OTHER_PICK_UP_TIME * DateHelper.HOUR_MILLIONS ||
                userEvent.getStatus() == eWingRoomEventStatus.Share.getStatus()) {
            return GameErrorCode.E_WING_ROOM_SHARE_EVENT_SHARE_LIMIT;  //不允许分享
        }
        String unionUid = player.getUserInfo().getUnionUid();
        if (shareType == 1) {
            if (StringUtils.isNullOrEmpty(unionUid)) {
                return GameErrorCode.E_UNION_NO_JOIN_UNION;
            }
        }
        //分享 shareType
        userEvent.setStatus(eWingRoomEventStatus.Share.getStatus());
        userEvent.setShareUnionUid(unionUid);
        pushShareMessage(userEvent, shareType);
        return 0;
    }

    private void pushShareMessage(UserWingRoomShareEvent userEvent, int shareType) {
        //商会频道消息
        if (shareType == 1) {
            pushUnionShareMessage(userEvent);
            //世界消息
        } else if (shareType == 2) {
            pushWorldShareMessage(userEvent);
        }
    }

    private void pushWorldShareMessage(UserWingRoomShareEvent userEvent) {
        String content = WingRoomMgr.buildShareMessageContent(userEvent);
        WorldMessageProto.WorldMessageTempMsg.Builder chatMsg = WorldMessagePb.parseWorldMessageTempMsg(player.getUserInfo(),
                eMessageType.WingRoomWorldShare.getValue(), eChatContentType.Common.getContentType(), content, System.currentTimeMillis(), 0, null);
        WorldMessageMgr.addWorldMessage(player, chatMsg);
    }


    private void pushUnionShareMessage(UserWingRoomShareEvent userEvent) {
        String content = WingRoomMgr.buildShareMessageContent(userEvent);
        WorldMessageProto.WorldMessageTempMsg.Builder chatMsg = WorldMessagePb.parseWorldMessageTempMsg(player.getUserInfo(),
                eMessageType.WingRoomUnionShare.getValue(), eChatContentType.Common.getContentType(), content, System.currentTimeMillis(), 0, null);
        WorldMessageMgr.addWorldMessage(player, chatMsg);
    }

    public void resetOneDay() {
        try {
            long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp();
            if (wingRoomData != null) {
                if (wingRoomData.getTimesResetTime() < zeroTime) {
                    wingRoomData.setGetEventRewardTimes(0);
                    wingRoomData.setPreGetEventRewardTimes(0);
                    wingRoomData.setTimesResetTime(zeroTime);
                }
            }
        } catch (Exception e) {
            log.error("wing-room resetOneDay error:playerId:{}, exception:{}", player.getUserId(), e);
        }

        try {
            int zeroTime = DateHelper.getTodayZeroTime();
            if (patronsVisitData != null) {
                if (patronsVisitData.getResetTime() < zeroTime) {
                    patronsVisitData.setTodayTouch(false);
                    patronsVisitData.setResetTime(zeroTime);
                }
            }
        } catch (Exception e) {
            log.error("wing-room resetOneDay patronsVisitData error:playerId:{}, exception:{}", player.getUserId(), e);
        }
    }

    //初始化数据
    public UserWingRoomData initWingRoomData() {
        if (wingRoomData == null) {
            wingRoomData = new UserWingRoomData(player.getUserId(), System.currentTimeMillis(), DataStatus.Insert);
            // 初始化厢房徽章
            updateBadge();
        }
        if (patronsVisitData == null){
            patronsVisitData = new UserPatronsVisitData();
            patronsVisitData.setUserId(player.getUserId());
            patronsVisitData.setState(2);//待初始事件
            patronsVisitData.setResetTime(DateHelper.getTodayZeroTime());
            patronsVisitData.setInsertOption();
        }
        return wingRoomData;
    }

    //重算厢房舒适度
    private void calcFurnitureComfortValue() {

        long comfortValue = 0L;
        for (UserFurnitureSample sample : furnitureMap.values()) {
            WingRoomFurnitureConfig furnitureConfig = WingRoomConfigMgr.getFurnitureConfig(sample.getFurnitureId());
            if (furnitureConfig == null) {
                continue;
            }
            for (Integer skill : furnitureConfig.getSkills()) {
                SkillInfo skillInfo = SkillMgr.getSkillInfo(skill);
                if (skillInfo == null) {
                    continue;
                }
                if (skillInfo.getType() == eSkillType.WingRoomComfortValueAdd.getValue()) {
                    comfortValue += SkillMgr.getSkillAddition(skillInfo, sample.getLv());
                }
            }
        }
        wingRoomData.setComfortValue(comfortValue);
        changeComfortValueRank();
    }

    //榜单变更
    private void changeComfortValueRank() {
        try {
            RankMgr.changeUserRank(eBigRankType.Normal.getValue(), player.getUserId(), BigInteger.valueOf(wingRoomData.getComfortValue()), eRankType.WingRoomComfortValue.getValue(), "" + wingRoomData.getLv());
        } catch (Exception ex) {
            log.error(ex);
        }
    }

    //家具套装等级升级
    public int furnitureSuitLvUp(int suitType) {
        List<WingRoomFurnitureConfig> suitFurnitureList = WingRoomConfigMgr.getSuitConfigMap().get(suitType);
        if (suitFurnitureList == null) {
            return GameErrorCode.E_WING_ROOM_FURNITURE_SUIT_TYPE_NO_FOUND;
        }
        int suitLv = 0;
        UserFurnitureSuitData suitData = suitDataMap.get(suitType);
        if (suitData == null) {
            suitData = new UserFurnitureSuitData(getUserId(), suitType, suitLv, DataStatus.Insert);
            suitDataMap.put(suitType, suitData);
        }
        suitLv = suitData.getSuitLv();

        int wantLv = suitLv + 1;
        for (WingRoomFurnitureConfig furnitureConfig : suitFurnitureList) {
            UserFurnitureSample furnitureSample = furnitureMap.get(furnitureConfig.getFurnitureId());
            if (!HideGoodsMgr.isFurnitureHide(furnitureConfig.getFurnitureId()) && (furnitureSample == null || furnitureSample.getLv() < wantLv)) {
                return GameErrorCode.E_WING_ROOM_FURNITURE_SUIT_LV_UP_LIMIT;
            }
        }
        //升级
        suitData.setSuitLv(wantLv);
        player.getModule(PatronsModule.class).onPatronsChange(null);
        return 0;
    }

    public UserFurnitureSuitData getSuitData(int suitType) {
        return suitDataMap.get(suitType);
    }

    public Map<Integer, UserFurnitureSuitData> getSuitDataMap() {
        return suitDataMap;
    }

    public UserFurnitureSample getFurnitureSample(int furnitureId) {
        return furnitureMap.get(furnitureId);
    }

    public Map<Integer, UserFurnitureSample> getFurnitureMap() {
        return furnitureMap;
    }

    @Override
    public boolean saveData() {
        if (wingRoomData != null) {
            if (wingRoomData.isInsertOption()) {
                new WingRoomDataDaoImpl().add(wingRoomData);
            } else if (wingRoomData.isUpdateOption()) {
                new WingRoomDataDaoImpl().update(wingRoomData);
            }
        }

        if (furnitureMap != null) {
            for (UserFurnitureSample data : furnitureMap.values()) {
                if (data.isInsertOption()) {
                    new UserFurnitureSampleDaoImpl().add(data);
                } else if (data.isUpdateOption()) {
                    new UserFurnitureSampleDaoImpl().update(data);
                }
            }
        }

        if (userPlanMap != null) {
            for (UserWingRoomPlan data : userPlanMap.values()) {
                if (data.isInsertOption()) {
                    new UserWingRoomPlanDaoImpl().add(data);
                } else if (data.isUpdateOption()) {
                    new UserWingRoomPlanDaoImpl().update(data);
                }
            }
        }

        if (suitDataMap != null) {
            for (UserFurnitureSuitData data : suitDataMap.values()) {
                if (data.isInsertOption()) {
                    new UserFurnitureSuitDaoImpl().add(data);
                } else if (data.isUpdateOption()) {
                    new UserFurnitureSuitDaoImpl().update(data);
                }
            }
        }

        if (patronsVisitData != null){
            if(patronsVisitData.isInsertOption()){
                DaoHelper.getUserPatronsVisitDataDaoImpl().add(patronsVisitData);
            }else if(patronsVisitData.isUpdateOption()){
                DaoHelper.getUserPatronsVisitDataDaoImpl().update(patronsVisitData);
            }
        }
        return true;
    }

    public void copyOtherPlayerPlan(Map<Integer, WingRoomRegion> planRegion, String planName, WingRoomProto.GetOtherPlanRespMsg.Builder respMsg) {
        addNewPlan(planRegion, planName);
        //统计家具数量
        HashSet<Integer> errFurnitureIdList = new HashSet<>();
        Map<Integer, Integer> usedNumMap = calcUsedFurniture(planRegion);
        for (Map.Entry<Integer, Integer> entry : usedNumMap.entrySet()) {
            if (getFurnitureCanPlaceCount(entry.getKey()) < entry.getValue()) {
                errFurnitureIdList.add(entry.getKey());
            }
        }
        respMsg.addAllFurnitureId(errFurnitureIdList);
    }

    /**
     * 精进技能上限加成
     * @return
     */
    public int getStageSkillMaxLevelAdd() {
        int addLv = 0;
        if (wingRoomData == null) {
            return addLv;
        }
        WingRoomLvConfig wingRoomLvConfig = WingRoomConfigMgr.getWingRoomLvConfig(wingRoomData.getLv());
        if (wingRoomLvConfig != null) {
            for (Integer skillId : wingRoomLvConfig.getSkillList()) {
                SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
                if (skillInfo != null && skillInfo.getType() == eSkillType.FishPondStageSkillMaxLevelAdd.getValue()) {
                    addLv += SkillMgr.getSkillAddition(skillInfo, wingRoomData.getLv());
                }
            }
        }
        return addLv;
    }

    public ReturnData recycleFurniture(List<WingRoomProto.RecycleFurnitureTempMsg> recycleFurnitureList) {
        ReturnData returnData = new ReturnData(0);
        Property reward = new Property();
        Property recycleFurniture = new Property();
        for (WingRoomProto.RecycleFurnitureTempMsg furnitureTempMsg : recycleFurnitureList) {
            WingRoomFurnitureConfig furnitureConfig = WingRoomConfigMgr.getFurnitureConfig(furnitureTempMsg.getFurnitureId());
            if (furnitureConfig == null) {
                returnData.setRet(GameErrorCode.E_WING_ROOM_CONFIG_NO_FOUND);
                return returnData;
            }
            Property property = PropertyHelper.parseStringToProperty(furnitureConfig.getPrice());

            property.rideProperty(BigDecimal.valueOf(((double) GameConfig.WINGROOM_FURNITURE_RECOVER_PROPORTION / 1000)));
            property.rideProperty(furnitureTempMsg.getNum());
            reward.addProperty(property);

            recycleFurniture.addProperty(new Property(furnitureTempMsg.getFurnitureId(), BigInteger.valueOf(furnitureTempMsg.getNum())));
        }
        if (!player.getModule(CurrencyModule.class).removeCurrency(recycleFurniture, eLogMoneyType.WingRoom, eLogMoneyType.WingRoomRecycleFurnitureCost)) {
            returnData.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
            return returnData;
        }
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.WingRoom, eLogMoneyType.WingRoomRecycleFurnitureGet);
        returnData.setParams(Collections.singletonList(PropertyHelper.parsePropertyToString(reward)));
        return returnData;

    }

    /**
     * 修改背景音乐
     */
    public int changeMusic(String music) {

        //未达解锁条件
        if(!furnitureMap.containsKey(GameConfig.WINGROOM_MUSIC_UNLOCK_COND)){
            return GameErrorCode.E_WING_ROOM_UN_REACH_MUSIC_UNLOCK_COND;
        }

        wingRoomData.setBgm(music);

        player.sendPacket(Protocol.U_WING_ROOM_CHANGE_BG_MUSIC, WingRoomProto.UserWingRoomChangeBgMusicRespMsg.newBuilder().setRet(0).setMusic(music));
        return 0;
    }

    /**
     * 触发门客拜访事件
     */
    public void touchUserPatronsVisitData(WingRoomProto.PullPlayerPatronsRespMsg respMsg){

        if(patronsVisitData == null){
            return;
        }
        //厢房等级不足
        if(wingRoomData.getLv() < GameConfig.WINGROOM_VISITOR_TRIGGER_LEVEL){
            return;
        }

        synchronized (this) {

            if (patronsVisitData.getState() != 2) {
                //未完成
                return;
            }

            //当日已触发
            if (patronsVisitData.isTodayTouch()){
                return;
            }

            if (patronsVisitData.getEventTime() > 0) {
                int zeroTime = DateHelper.getZeroTime(patronsVisitData.getEventTime());
                //当日已触发
                if (zeroTime == DateHelper.getTodayZeroTime()) {
                    return;
                }
            }
            //是否触发时间点
            if(DateHelper.getHours() < GameConfig.WINGROOM_VISITOR_TRIGGER_TIME){
                return;
            }

            if (respMsg != null) {
                Map<Integer, UserPatrons> topMap = new HashMap<>();
                for (WingRoomProto.VisitPatronsTempMsg tempMsg : respMsg.getPatronsList()) {
                    UserPatrons patrons = new UserPatrons();
                    patrons.setAbility(new BigInteger(tempMsg.getAbility()));
                    patrons.setLevel(tempMsg.getLevel());
                    patrons.setPatronsId(tempMsg.getPatronsId());
                    patrons.setPromotionId((int) tempMsg.getPromotionId());
                    patrons.setSkinId(tempMsg.getSkinId());
                    patrons.setStageLv(tempMsg.getStageLv());
                    topMap.put(patrons.getPatronsId(), patrons);
                }
                UserBaseInfo userBaseInfo = PlayerBasePb.parseToUserBaseInfo(respMsg.getBaseInfo());
                touchUserPatronsVisitData(respMsg.getUserId(), topMap, userBaseInfo);
                return;
            }

            Random random = new Random();
            //触发概率
            if(random.nextInt(1000) >= GameConfig.WINGROOM_VISITOR_TRIGGER_WEIGHT){
                patronsVisitData.setTodayTouch(true);
                return;
            }

            //随机好友
            Map<Long, RelativesInfo> relativesInfoMap = player.getModule(RelativesModule.class).getRelativesMap();
            if (relativesInfoMap.size() > 0) {
                List<RelativesInfo> list = new ArrayList<>(relativesInfoMap.values());
                //过滤已解除的亲家关系
                list.removeIf(info -> info.getStatus() == 0);
                if(list.size() > 0) {
                    int idx = random.nextInt(list.size());
                    RelativesInfo relativesInfo = list.get(idx);
                    long friendId;
                    if (relativesInfo.getUserId1() == player.getUserId()) {
                        friendId = relativesInfo.getUserId2();
                    } else {
                        friendId = relativesInfo.getUserId1();
                    }
                    //是否跨服亲家
                    long relativeServerId = RelativesMgr.getUserServerId(friendId);
                    if(relativeServerId != GameServer.getInstance().getServerId()){
                        //跨服去拉玩家、门客数据
                        WingRoomProto.CrossWatchOtherPlayerReqMsg.Builder reqMsg = WingRoomProto.CrossWatchOtherPlayerReqMsg.newBuilder();
                        reqMsg.setWatchPlayerId(player.getUserId());
                        reqMsg.setOriginPlayerId(friendId);   //目标玩家id
                        reqMsg.setOriginServerId(relativeServerId); //目标玩家区服
                        player.sendPacket(Protocol.C_WING_ROOM_CROSS_PULL_PLAYER_PATRONS, reqMsg);
                        return;
                    }
                    Map<Integer, UserPatrons> topMap = WingRoomMgr.getTopUserPatrons(friendId);
                    UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(friendId, GameServer.getInstance().getServerId());
                    touchUserPatronsVisitData(friendId, topMap, userBaseInfo);
                    return;
                }
            }

            //随机盟友
            if (!StringUtils.isNullOrEmpty(player.getUserInfo().getUnionUid())) {
                Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(player.getUserInfo().getUnionUid());
                List<CrossUnionMember> list = new ArrayList<>();
                if (memberMap != null) {
                    for (Map.Entry<Long, CrossUnionMember> memberEntry : memberMap.entrySet()) {
                        if(memberEntry.getValue().getUserId() == player.getUserId()){
                            continue;
                        }
                        list.add(memberEntry.getValue());
                    }
                    if (list.size() > 0) {
                        int idx = random.nextInt(list.size());
                        CrossUnionMember member = list.get(idx);
                        if (member.getServerId() == GameServer.getInstance().getServerId()) {
                            UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(member.getUserId(), GameServer.getInstance().getServerId());
                            Map<Integer, UserPatrons> topMap = WingRoomMgr.getTopUserPatrons(member.getUserId());
                            touchUserPatronsVisitData(member.getUserId(), topMap, userBaseInfo);
                        } else {
                            //跨服去拉玩家、门客数据
                            WingRoomProto.CrossWatchOtherPlayerReqMsg.Builder reqMsg = WingRoomProto.CrossWatchOtherPlayerReqMsg.newBuilder();
                            reqMsg.setWatchPlayerId(player.getUserId());
                            reqMsg.setOriginPlayerId(member.getUserId());   //目标玩家id
                            reqMsg.setOriginServerId(member.getServerId()); //目标玩家区服
                            player.sendPacket(Protocol.C_WING_ROOM_CROSS_PULL_PLAYER_PATRONS, reqMsg);
                        }
                        return;
                    }
                }
            }

            //随机区服非亲友、盟友
            List<Long> userIdList = GamePlayerMgr.getAllOnlinePlayerId();
            if (userIdList.size() > 1) {
                int idx = random.nextInt(userIdList.size());
                long userId = userIdList.get(idx);
                while (userId == player.getUserId()) {
                    idx = random.nextInt(userIdList.size());
                    userId = userIdList.get(idx);
                }
                UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(userId, GameServer.getInstance().getServerId());
                Map<Integer, UserPatrons> topMap = WingRoomMgr.getTopUserPatrons(userId);
                touchUserPatronsVisitData(userId, topMap, userBaseInfo);
                return;
            }else {
                List<UserInfo> userInfoList = UserMgr.getUserInfoList();
                if(userInfoList.size() > 0){
                    int idx = random.nextInt(userInfoList.size());
                    UserInfo user = userInfoList.get(idx);
                    while (user.getUserId() == player.getUserId()){
                        idx = random.nextInt(userInfoList.size());
                        user = userInfoList.get(idx);
                    }
                    UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(user.getUserId(), GameServer.getInstance().getServerId());
                    Map<Integer, UserPatrons> topMap = WingRoomMgr.getTopUserPatrons(user.getUserId());
                    touchUserPatronsVisitData(user.getUserId(), topMap, userBaseInfo);
                }
            }
        }

    }

    /**
     * 构建门客来访事件
     */
    private void touchUserPatronsVisitData(long visitor, Map<Integer, UserPatrons> topMap, UserBaseInfo visitorBaseInfo) {
        patronsVisitData.setState(0);
        patronsVisitData.setEventTime(DateHelper.getCurrentSecond());
        patronsVisitData.setVisitor(visitor);
        patronsVisitData.setUserBaseInfo(visitorBaseInfo);
        patronsVisitData.setTodayTouch(true);
        List<WingRoomVisitPatrons> patronsList = new ArrayList<>();
        for (Map.Entry<Integer, UserPatrons> patronsEntry : topMap.entrySet()) {
            WingRoomVisitPatrons patrons = new WingRoomVisitPatrons();
            UserPatrons userPatrons = patronsEntry.getValue();
            patrons.setAbility(userPatrons.getAbility().toString());
            patrons.setLevel(userPatrons.getLevel());
            patrons.setPatronsId(userPatrons.getPatronsId());
            patrons.setPromotionId(userPatrons.getShowPromotionId());
            patrons.setSkinId(userPatrons.getSkinId());
            patrons.setStageLv(userPatrons.getStageLv());
            patronsList.add(patrons);
        }
        patronsVisitData.setPatronsList(patronsList);

        syncVisitPatrons();

        AutoLogMgr.add(new LogWingRoomPatronsVisit(player.getUserId(), visitor, patronsList));
    }

    /**
     * 检测门客拜访事件是否结束
     */
    public void checkUserPatronsVisitData(){

        if(patronsVisitData == null){
            return;
        }

        synchronized (this){

            if(patronsVisitData.getState() == 2 || patronsVisitData.getState() == 0){
                return;
            }

            if(patronsVisitData.getDoneTime() > DateHelper.getCurrentSecond()){
                return;
            }

            patronsVisitData.setState(2);
            //重复设置一次，隔天的事件在当日按18点后才完成的，也算今日已触发过，不可以再触发
            //是否触发时间点
            if(DateHelper.getHours() >= GameConfig.WINGROOM_VISITOR_TRIGGER_TIME){
                patronsVisitData.setTodayTouch(true);
            }

            syncVisitPatrons();

            //奖励自己
            String title = MultipleLanguageMgr.getContent(MailManager.WINGROOM_VISIT_OWNER_TITLE, player.getUserInfo().getLanguage());
            String content = MultipleLanguageMgr.getContent(MailManager.WINGROOM_VISIT_OWNER_CONTENT, player.getUserInfo().getLanguage());
            MailManager.sendMail(player.getUserId(), eMailType.DAILY.getValue(), GameConfig.WINGROOM_VISIT_REWARD_OWNER, content, title);

            //奖励访客(本服且当前在线)
            if(patronsVisitData.getUserBaseInfo().getServerId() == GameServer.getInstance().getServerId()){
                GamePlayer guest = GamePlayerMgr.getOnlinePlayer(patronsVisitData.getVisitor());
                if(guest != null){
                    sendVisitRewardMail(guest, GameConfig.WINGROOM_VISIT_REWARD_GUEST, GameServer.getInstance().getServerId(), player.getUserInfo().getNickName());
                    return;
                }
            }
            //奖励访客       //上跨服
            WingRoomProto.CrossUserVisitRewardSendUploadMsg.Builder uploadMsg = WingRoomProto.CrossUserVisitRewardSendUploadMsg.newBuilder();
            uploadMsg.setUserId(patronsVisitData.getVisitor());
            uploadMsg.setEndTime(patronsVisitData.getDoneTime());
            uploadMsg.setReward(GameConfig.WINGROOM_VISIT_REWARD_GUEST);
            uploadMsg.setHomeUser(player.getUserId());
            player.sendPacket(Protocol.C_WING_ROOM_CROSS_SEND_VISIT_REWARD, uploadMsg);
        }

    }

    public void sendVisitRewardMail(GamePlayer guest, String rewards, long homeUserServerId, String homeUserNickName) {
        List<UserMail> mailList = guest.getModule(MailModule.class).getShowMailList();
        String guestTitle = MultipleLanguageMgr.getContent(MailManager.WINGROOM_VISIT_GUEST_TITLE, guest.getUserInfo().getLanguage());
        for (UserMail mail : mailList) {
            //未领取时，不发奖励
            if(Objects.equals(mail.getTitle(), guestTitle) && Objects.equals(mail.getAnnexes(), rewards)
                    && !mail.isGetReward()){
                return;
            }
        }
        ServerInfo serverInfo = ServerListMgr.getServerInfo(homeUserServerId);
        String serverName = "";
        if(serverInfo != null){
            serverName = serverInfo.getServerName();
        }
        String guestContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.WINGROOM_VISIT_GUEST_CONTENT, guest.getLanguage()), serverName, homeUserNickName);
        MailManager.sendMail(guest.getUserId(), eMailType.DAILY.getValue(), rewards, guestContent, guestTitle);
    }

    /**
     * 同步来访门客
     */
    private void syncVisitPatrons() {

        if(patronsVisitData == null){
            return;
        }

        WingRoomProto.UserVisitPatronsSync.Builder sync = WingRoomPb.buildUserVisitPatronsSync(patronsVisitData);

        player.sendPacket(Protocol.U_WING_ROOM_PATRONS_VISIT_EVENT_SYNC, sync);

    }

    /**
     * 接待拜访
     */
    public int receiveVisit() {

        if(patronsVisitData.getState() != 0){
            return 0;
        }

        patronsVisitData.setState(1);
        patronsVisitData.setReceiveTime(DateHelper.getCurrentSecond());
        patronsVisitData.setDoneTime(patronsVisitData.getReceiveTime() + (int)(GameConfig.WINGROOM_VISITOR_VISIT_TIME * DateHelper.MINUTE_SECONDS) );

        WingRoomProto.UserVisitPatronsSync.Builder sync = WingRoomPb.buildUserVisitPatronsSync(patronsVisitData);
        WingRoomProto.ReceiveUserVisitPatronsRespMsg.Builder respMsg = WingRoomProto.ReceiveUserVisitPatronsRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setVisit(sync);
        player.sendPacket(Protocol.U_WING_ROOM_PATRONS_VISIT_RECEIVE, respMsg);
        return 0;
    }

    public void fetchCrossVisitReward(){
        player.sendPacket(Protocol.C_WING_ROOM_CROSS_GET_VISIT_REWARD, WingRoomProto.CrossGetVisitRewardReqMsg.newBuilder());
    }

    public void syncRedDot(WingRoomProto.UserWingRoomRedDotSync.Builder sync){
        player.sendPacket(Protocol.U_WING_ROOM_USER_RED_DOT_SYNC, sync);
    }

    /**
     * 计算拜访红点
     */
    public void calVisitRedDot(WingRoomProto.UserWingRoomRedDotSync.Builder sync){
        if (wingRoomData == null){
            return;
        }

        //沒有领取次数
        if (wingRoomData.getTotalGetEventRewardTimes() >= GameConfig.WINGROOM_FIND_FRIENDS_PICK_UP_OTHER_NUM) {
            syncRedDot(sync.setVisit(0));
            return;
        }

        //判定好友是否有跨服商会成员，沒有则本服直接计算
        //亲友+盟友
        Map<Long, Set<Long>> friendMap = new HashMap<>();
        List<Long> userList = new ArrayList<>();
        userList.add(player.getUserId());
        WingRoomMgr.getAllFriendMap(userList, friendMap);

        if(friendMap.size() > 1){
            //上跨服
            WingRoomProto.CrossCalEventRedDotReqMsg.Builder reqMsg = WingRoomProto.CrossCalEventRedDotReqMsg.newBuilder();
            for (Map.Entry<Long, Set<Long>> longSetEntry : friendMap.entrySet()) {
                reqMsg.addAllFriend(longSetEntry.getValue());
            }
            player.sendPacket(Protocol.C_WING_ROOM_CROSS_CAL_EVENT_RED_DOT, reqMsg);
            return;
        }

        //本服红点计算
        int canVisitList = 0;
        Set<Long> friendSet = friendMap.get(GameServer.getInstance().getServerId());
        if(friendSet != null){
            for (Long friendId : friendSet) {
                UserWingRoomShareEvent shareEvent = WingRoomMgr.getUserEvent(friendId);
                if(shareEvent == null){
                    continue;
                }
                if(WingRoomMgr.isDuringEventShare(shareEvent, player.getUserId()) == 0){
                    canVisitList = 1;
                    break;
                }
            }
        }
        sync.setVisit(canVisitList);
        syncRedDot(sync);
    }

    public void calVisitRedDotFromCross(int visit){
        WingRoomProto.UserWingRoomRedDotSync.Builder builder = WingRoomProto.UserWingRoomRedDotSync.newBuilder();
        if(visit == 0){
            syncRedDot(builder.setVisit(0));
            return;
        }
        //沒有领取次数
        if (wingRoomData.getTotalGetEventRewardTimes() >= GameConfig.WINGROOM_FIND_FRIENDS_PICK_UP_OTHER_NUM) {
            syncRedDot(builder.setVisit(0));
        }else {
            syncRedDot(builder.setVisit(1));
        }
    }


    /**
     * 更新勋章
     */
    public void updateBadge(){
        if (SystemOpenMgr.systemOpen(player, eSystemId.BadgeShow.getValue())) {
            if (wingRoomData == null) {
                return;
            }
            WingRoomLvConfig wingRoomCurLvConfig = WingRoomConfigMgr.getWingRoomLvConfig(wingRoomData.getLv());
            if (wingRoomCurLvConfig == null) {
                return;
            }
            player.getModule(BadgeModule.class).addBadge(wingRoomCurLvConfig.getId(), eBadgeType.WingRoom.getValue());
        }
    }

}
